using System;
using System.Linq;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Lime49;
using System.Runtime.InteropServices;
using System.Collections;
using LockCrypt.Core;
using LockCrypt.DAL;

namespace LockCrypt.Mobile {
    /// <summary>
    /// A form for displaying an Account.
    /// </summary>
    public partial class FrmShowAccount : Form {
        private Font fieldNameFont = WMConstants.FieldNameFont;
        private Font fieldValueFont = WMConstants.FieldValueFont;
        private int fontHeight;
        private int fieldSpacingY = WMConstants.FieldSpacingY;
        private IAccount account;

        private static long PMCF_DEFAULT = 0x00000001;
        private static long PMCF_PROMPTBEFORECALLING = 0x00000002;
        private struct PhoneMakeCallInfo {
            public IntPtr cbSize;
            public IntPtr dwFlags;
            public IntPtr pszDestAddress;
            public IntPtr pszAppName;
            public IntPtr pszCalledParty;
            public IntPtr pszComment;

        }

        [DllImport("phone.dll")]
        private static extern IntPtr PhoneMakeCall(ref PhoneMakeCallInfo ppmci);

        /// <summary>
        /// Makes a phone call using the Win32 API.
        /// </summary>
        /// <param name="PhoneNumber">The phone number to dial.</param>
        /// <param name="PromptBeforeCall">If set to <c>true</c> prompts the user before initiating the call.</param>
        unsafe private static void MakeCall(string PhoneNumber, bool PromptBeforeCall) {
            IntPtr res;
            PhoneNumber += '\0';
            char[] cPhoneNumber = PhoneNumber.ToCharArray();
            fixed (char* pAddr = cPhoneNumber) {
                PhoneMakeCallInfo info = new PhoneMakeCallInfo();
                info.cbSize = (IntPtr)Marshal.SizeOf(info);
                info.pszDestAddress = (IntPtr)pAddr;
                if(PromptBeforeCall) {
                    info.dwFlags = (IntPtr)PMCF_PROMPTBEFORECALLING;
                } else {
                    info.dwFlags = (IntPtr)PMCF_DEFAULT;
                }
                res = PhoneMakeCall(ref info);
            }
        }


        /// <summary>
        /// Initializes a new Account display form.
        /// </summary>
        /// <param name="account">The Account to show.</param>
        public FrmShowAccount(IAccount account) {
            InitializeComponent();
            this.account = account;
            ITemplate template = DalConfigurationManager.Provider.GetTemplateByID(account.Template.ID);
            if(template == null) {
                account.Template = new TemplateBase() {
                    Name = I18nUtils.GetString("Errors", "Error"),
                    ID = account.Template.ID,
                    ShowNotes = true
                };
            } else {
                account.Template = template;
            }
            itmBack.Click += (s, e) => {
                this.DialogResult = DialogResult.OK;
            };
            itmEdit.Click += (s, e) => {
                using(FrmEditAccount frmEditAccount = new FrmEditAccount(this.account)) {
                    if(frmEditAccount.ShowDialog() == DialogResult.OK) {
                        this.account = frmEditAccount.Account;
                        try {
                            DalConfigurationManager.Provider.EditAccount(this.account);
                        } catch(Exception ex) {
                            MessageBox.Show(ex.Message, I18nUtils.GetString("Errors", "Error"), MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
                        }
                        ShowFields();
                    }
                }
            };
            ShowFields();
        }

        /// <summary>
        /// Shows the fields in this account.
        /// </summary>
        private void ShowFields() {
            lblName.Text = account.Name;
            this.SuspendLayout();
            Controls.Clear();
            this.Controls.Add(this.lblTypeValue);
            this.Controls.Add(this.lblTypeName);
            this.Controls.Add(this.lblName);
            this.Controls.Add(this.pctIcon);
            int curY = lblTypeName.Top + lblTypeName.Height + fieldSpacingY;
            using(Graphics g = this.CreateGraphics()) {
                // Font in the Compact Framework lacks the Height property
                fontHeight = (int)Math.Ceiling(g.MeasureString("y", fieldNameFont).Height);
                Utils.FitFontSizeToLabel(g, lblName);
                //pctIcon.Image = (Image)Properties.Resources.ResourceManager.GetObject(account.Icon + "_64");
                pctIcon.Image = WinMobileUtils.GetSizedImage(account.Icon, 32);
                lblTypeName.Font = fieldNameFont;
                lblTypeName.Height = fontHeight;
                lblTypeValue.Text = account.Template.Name;
                lblTypeValue.Font = fieldValueFont;
                lblTypeValue.Height = Utils.EnlargeLabelToText(g, lblTypeValue, fontHeight);
                foreach(IField field in account.Fields) {
                    string fieldName = field.Name,//.Key.ToString(),
                           fieldValue = field.Value;//.ToString();
                    if(fieldValue.Length > 0) {
                        Label lblFieldName = new Label {
                            Location = new Point(lblTypeName.Left, curY),
                            Font = fieldNameFont,
                            Width = lblTypeName.Width,
                            Text = fieldName
                        };
                        Controls.Add(lblFieldName);

                        Label lblFieldValue = new Label {
                            Location = new Point(lblTypeValue.Left, curY),
                            Font = fieldValueFont,
                            Text = fieldValue,
                            Width = lblTypeValue.Width
                        };
                        if(FieldBase.GetMetaState(field.Meta, FieldMetaData.Password)) {
                            lblFieldValue.Text = "******";
                            lblFieldValue.Width = lblTypeValue.Width - 18;
                            ImageButton btnReveal = new ImageButton((Image) Properties.Resources.ResourceManager.GetObject("peek_16x16")) {Size = new Size(18, 18), Location = new Point(lblFieldValue.Left + lblFieldValue.Width + 2, curY)};
                            string hiddenText = fieldValue; // make a copy of the field value because it will always hold the last field in the account
                            btnReveal.Click += (sender, e) => RevealField(lblFieldName.Text, hiddenText);
                            Controls.Add(btnReveal);
                        }
                        if(FieldBase.GetMetaState(field.Meta, FieldMetaData.Password)) {
                            lblFieldValue.Width = lblTypeValue.Width - 18;
                            ImageButton btnCall = new ImageButton((Image) Properties.Resources.ResourceManager.GetObject("phone_16x16")) {Size = new Size(18, 18), Location = new Point(lblFieldValue.Left + lblFieldValue.Width + 2, curY)};
                            string numberToCall = fieldValue;
                            btnCall.Click += ((sender, e) => MakeCall(numberToCall));
                            Controls.Add(btnCall);
                        }
                        
                        Controls.Add(lblFieldValue);

                        lblFieldValue.Height = Utils.EnlargeLabelToText(g, lblFieldValue, fontHeight);
                        lblFieldName.Height = Utils.EnlargeLabelToText(g, lblFieldName, fontHeight);

                        curY += lblFieldName.Height > lblFieldValue.Height ?
                                    lblFieldName.Height + fieldSpacingY : lblFieldValue.Height + fieldSpacingY;
                    }
                }
                if(account.Template.ShowNotes && account.Notes.Trim().Length > 0) {
                    Label lblNotesName = new Label {
                        Text = "Notes",
                        Location = new Point(lblTypeName.Left, curY),
                        Font = fieldNameFont,
                        Size = new Size(lblTypeName.Width, lblTypeName.Height)
                    };
                    Controls.Add(lblNotesName);

                    Label lblNotesValue = new Label {
                        Text = account.Notes,
                        Font = fieldValueFont,
                        Location = new Point(lblTypeValue.Left, curY),
                        Width = lblTypeValue.Width
                    };
                    lblNotesValue.Height = Utils.EnlargeLabelToText(g, lblNotesValue, fontHeight);
                    Controls.Add(lblNotesValue);

                    curY += lblNotesName.Height + fieldSpacingY;
                }
            }
            this.ResumeLayout();
        }

        /// <summary>
        /// Shows an obfuscated field as a messagebox.
        /// </summary>
        /// <param name="fieldName">Name of the field.</param>
        /// <param name="hiddenValue">The hidden value to show.</param>
        private static void RevealField(string fieldName, string hiddenValue) {
            MessageBox.Show(hiddenValue, fieldName, MessageBoxButtons.OK, MessageBoxIcon.Asterisk, MessageBoxDefaultButton.Button1);
        }

        /// <summary>
        /// Initiates a phone call to the specified number.
        /// </summary>
        /// <param name="number">The number to dial.</param>
        private static void MakeCall(string number) {
            MakeCall(number, false);
        }
    }
}